home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / dump / main.c < prev    next >
C/C++ Source or Header  |  1992-03-28  |  46KB  |  1,974 lines

  1. /*
  2.  * main.c --
  3.  *
  4.  *      Main routine for the sprite dump program.
  5.  *
  6.  *
  7.  * Copyright 1988 Regents of the University of California
  8.  * Permission to use, copy, modify, and distribute this
  9.  * software and its documentation for any purpose and without
  10.  * fee is hereby granted, provided that the above copyright
  11.  * notice appear in all copies.  The University of California
  12.  * makes no representations about the suitability of this
  13.  * software for any purpose.  It is provided "as is" without
  14.  * express or implied warranty.
  15.  */
  16.  
  17. #ifndef lint
  18. static char rcsid[] = "$Header: /sprite/src/admin/dump/RCS/main.c,v 1.12 92/03/28 17:29:31 kupfer Exp $";
  19. #endif
  20.  
  21. #include <sprite.h>
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25. #include <ctype.h>
  26. #include <fcntl.h>
  27. #include <signal.h>
  28. #include <time.h>
  29. #include <pwd.h>
  30. #include <unistd.h>
  31. #include <sys/types.h>
  32. #include <sys/stat.h>
  33. #include <sys/wait.h>
  34. #include <sys/param.h>
  35. #include <sys/dir.h>
  36. #include <option.h>
  37. #include <fs.h>
  38. #include <dev/tape.h>
  39. #include <status.h>
  40. #include <cfuncproto.h>
  41. #include <varargs.h>
  42. #include <assert.h>
  43. #include <dev/exabyte.h>
  44. #include <bstring.h>
  45. #include <sys/errno.h>
  46.  
  47. #define DEBUG
  48.  
  49. #ifdef DEBUG
  50. #define debugp(x) ((void) fprintf x, fflush(stderr))
  51. #else
  52. #define debugp(x)
  53. #endif
  54.  
  55. #define SPRITE_OLD_DUMP_HEADER "SPRITE DUMP TAPE #"
  56. #define SPRITE_DUMP_HEADER     "SPRITE DUMP TAPE,"
  57. #define SPRITE_DUMP_INFO    " Version %d Level %d Tape %d"
  58. #define SPRITE_DUMP_VERSION    1
  59.  
  60. #define DUMPDATES                  "/sprite/admin/dump/dumpdates"
  61. #define LOGFILE                 "/sprite/admin/dump/dumplog"
  62. #define DRIVELOG        "/sprite/admin/dump/statuslog"
  63. #define TAR                   "tar.gnu"
  64.  
  65. #define KBytes(n)    (n * 1024)
  66. #define MBytes(n)    (1024 * KBytes(n))
  67.  
  68. #define    IOBUF_SIZE    KBytes(62)    /* Exebyte likes 62KB chunks */
  69.  
  70. #define TOC_SIZE_OLD     MBytes(10)    /* TOC occupied 10 MB on the tape */
  71. #define    TOC_USEABLE_OLD    MBytes(2)    /* About 2 MB of it can be used */
  72.  
  73. #define TOC_SIZE     KBytes(16)    /* No longer needs to be big. */
  74. #define    TOC_USEABLE    TOC_SIZE    /* and we can use it all */
  75.  
  76. #define TAR_BLOCK_SIZE    KBytes(64)    /* Do the tar in 64K blocks. */
  77.  
  78. #define LABEL_SIZE_OLD    IOBUF_SIZE    /* Size of useable label. */
  79. #define LABEL_SIZE    TOC_SIZE    /* Size of useable label. */
  80.  
  81. static char tapeBuffer[IOBUF_SIZE];
  82. static char *directoryToDump;
  83. static tarChild;
  84. static int pipefd[2];
  85. static int archivefd;
  86. static int dumpLevel = 0;
  87. static int tapeNumber;
  88. static int tapeLevel;
  89. static int fileNumber;
  90. static int verbose;
  91. static char *archiveFileName;
  92. static char *mailWho;
  93. static time_t lastTime;
  94. static time_t startTime;
  95. static int fatalErrors;
  96. static int nonFatalErrors;
  97. static int archiveFileIsATapeDrive;
  98. static int printTOC;
  99. static int progArgc;
  100. static char **progArgv;
  101. static int reInitialize = 0;
  102. static int reInitializeSafe = 0;
  103. static long totalBytes;
  104. static int debug;
  105. static int oldFormat;
  106. static int tarBlocks;
  107. static int tapePosition = 0;
  108. static int version = 0;
  109. static int labelSize = 0;
  110. static int lastFile;
  111. static int official = 1;
  112. #ifdef PROG_RESTORE
  113. static int printContents = 0;
  114. #endif
  115.  
  116. #ifdef PROG_DUMP
  117. static int resetAccessTimes;
  118.  
  119. static Option OptionArray[] = {
  120.   { OPT_TRUE,   "a", (char *) &resetAccessTimes, "Reset access times"        },
  121.   { OPT_TRUE,   "d", (char *) &debug,            "Debug"                     },
  122.   { OPT_STRING, "f", (char *) &archiveFileName,  "Name of archive file"      },
  123.   { OPT_INT,    "i", (char *) &tapeNumber,       "Initialize the tape"       },
  124.   { OPT_INT,    "l", (char *) &dumpLevel,        "Dump level (0-9)"          },
  125.   { OPT_STRING, "m", (char *) &mailWho,          "Send mail upon completion" },
  126.   { OPT_TRUE,   "r", (char *) &reInitialize,     "Re-initialize the tape"    },
  127.   { OPT_TRUE,   "s", (char *) &reInitializeSafe, "Safely re-initialize tape" },
  128.   { OPT_TRUE,   "t", (char *) &printTOC,         "Print table of contents"   },
  129.   { OPT_TRUE,   "v", (char *) &verbose,          "Verbose"                   },
  130.   { OPT_FALSE,   "u", (char *) &official,           "Unofficial dump"           },
  131. };
  132. #endif
  133.  
  134. #ifdef PROG_RESTORE
  135. static int relativePaths;
  136. static Option OptionArray[] = {
  137.   { OPT_STRING, "f", (char *) &archiveFileName,  "Name of archive"           },
  138.   { OPT_TRUE,   "d", (char *) &debug,            "Debug"                     },
  139.   { OPT_INT,    "n", (char *) &fileNumber,       "File number to use"        },
  140.   { OPT_TRUE,   "r", (char *) &relativePaths,    "Use relative pathnames"    },
  141.   { OPT_TRUE,   "t", (char *) &printTOC,         "Print table of contents"   },
  142.   { OPT_TRUE,   "v", (char *) &verbose,          "Verbose"                   },
  143.   { OPT_TRUE,   "T", (char *) &printContents,    "Print contents of dump file"},
  144. };
  145. #endif
  146.  
  147. static void cleanup_sighup _ARGS_((int sig));
  148. static void cleanup_sigint _ARGS_((int sig));
  149. static void cleanup_sigquit _ARGS_((int sig));
  150. static void cleanup_sigpipe _ARGS_((int sig));
  151. static void cleanup_sigterm _ARGS_((int sig));
  152.  
  153. static void openArchiveFile _ARGS_((void));
  154. static void forkOffTar _ARGS_((void));
  155. static void dumpDirectory _ARGS_((char *dir));
  156. static void initializeTape _ARGS_((void));
  157. static void sendMail _ARGS_((const char *msg));
  158. static void rewindTape _ARGS_((void));
  159. static void fatal _ARGS_((char *fmt, ...));
  160. static void warning _ARGS_((char *fmt, ...));
  161. static void readTapeLabel _ARGS_((void));
  162. static void rewindTape _ARGS_((void));
  163. static void openLog _ARGS_((void));
  164. static void skipOverFiles _ARGS_((void));
  165. #ifdef PROG_RESTORE
  166. static void findLastFile _ARGS_((void));
  167. #endif
  168. static void waitForChildToDie _ARGS_((void));
  169. static void setFileNumber _ARGS_((void));
  170. static void quote_string _ARGS_((char *to, const char *from));
  171. static void checkTape _ARGS_((void));
  172. static int parseDumpInfo _ARGS_((char *buf));
  173. static void gotoEOD _ARGS_((void));
  174. static ReturnStatus skipFiles _ARGS_((int num));
  175.  
  176. #ifdef PROG_DUMP
  177. static int  getNextDumpDateEntry _ARGS_((void));
  178. static void writeTapeLabel _ARGS_((void));
  179. static void flushOutput _ARGS_((void));
  180. static void getDumpDate _ARGS_((void));
  181. static void recordTime _ARGS_((void));
  182. #endif
  183.  
  184. #ifdef __STDC__
  185. #define VOID void
  186. #endif
  187.  
  188. void
  189. main(argc, argv)
  190.     int argc;
  191.     char **argv;
  192. {
  193.     uid_t    root;
  194.     uid_t    dumper;
  195.     struct passwd    *pwPtr;
  196.     uid_t    euid;
  197.     extern    uid_t    geteuid();
  198.     extern    int    setreuid();
  199. #ifdef PROG_DUMP
  200.     ReturnStatus    status;
  201. #endif
  202.     char         *date;
  203.     int            i;
  204.  
  205.  
  206.     signal(SIGHUP, cleanup_sighup);
  207.     signal(SIGINT, cleanup_sigint);
  208.     signal(SIGQUIT, cleanup_sigquit);
  209.     signal(SIGPIPE, cleanup_sigpipe);
  210.     signal(SIGTERM, cleanup_sigterm);
  211.     startTime = time(0L);
  212.     date = asctime(localtime(&startTime));
  213.     date[24] = '\0';
  214.     debugp((stderr, "\n"));
  215.     for (i = 0; i < argc; i++) {
  216.     debugp((stderr, "%s ", argv[i]));
  217.     }
  218.     debugp((stderr, "\n"));
  219.     debugp((stderr, "%s\n", date));
  220.     argc = Opt_Parse(argc, argv, OptionArray, Opt_Number(OptionArray), 0);
  221.     progArgc = argc;
  222.     progArgv = argv;
  223.  
  224.     pwPtr = getpwnam("root");
  225.     if (pwPtr != (struct passwd *) 0) {
  226.         root = pwPtr->pw_uid;
  227.     pwPtr = getpwnam("dumper");
  228.     if (pwPtr != (struct passwd *) 0) {
  229.         dumper = pwPtr->pw_uid;
  230.         euid = geteuid();
  231.         if (euid == root && setreuid(dumper, -1) != 0) {
  232.         perror("Couldn't set real userID to dumper");
  233.         exit(1);
  234.         }
  235.     }
  236.     }
  237.     endpwent();
  238.  
  239.     if ((TAR_BLOCK_SIZE & (512 - 1)) != 0) {
  240.     fatal("Tar block size must be multiple of 512\n");
  241.     }
  242.     tarBlocks = TAR_BLOCK_SIZE / 512;
  243.     oldFormat = 0;
  244.     openLog();
  245.     if (archiveFileName == NULL) {
  246.     fatal("No archive file specified");
  247.     }
  248.     tapeLevel = dumpLevel;
  249.     if (tapeNumber != 0) {
  250.     openArchiveFile();
  251.     initializeTape();
  252.     close(archivefd);
  253.     if (argc < 2) {
  254.         exit(EXIT_SUCCESS);
  255.     }
  256.     }
  257.     openArchiveFile();
  258.     if (archiveFileIsATapeDrive) {
  259.     readTapeLabel();
  260.     if (reInitialize || reInitializeSafe) {
  261.         if (reInitializeSafe) {
  262.         checkTape();
  263.         }
  264.         initializeTape();
  265.         close(archivefd);
  266.         if (argc < 2) {
  267.         exit(EXIT_SUCCESS);
  268.         }
  269.         openArchiveFile();
  270.     }
  271.     }
  272.     if (printTOC) {
  273.     if (!archiveFileIsATapeDrive) {
  274.         fatal("Cannot print TOC: Archive is not a tapeDrive");
  275.     }
  276.     fprintf(stderr, "%s\n", tapeBuffer);
  277.     if (argc < 2) {
  278.         exit(EXIT_SUCCESS);
  279.     }
  280.     }
  281.     if (argc < 2) {
  282.     Opt_PrintUsage(argv[0], OptionArray, Opt_Number(OptionArray));
  283.     exit(EXIT_FAILURE);
  284.     }
  285. #ifdef PROG_DUMP
  286.     directoryToDump = argv[1];
  287.     debugp((stderr, "dumping %s\n", directoryToDump));
  288.     if (archiveFileIsATapeDrive) {
  289.     setFileNumber();
  290.     if (oldFormat) {
  291.         skipOverFiles();
  292.     } else {
  293.         /* 
  294.          * We are currently at the end of the label since we just read
  295.          * it.  The tar file will follow the subsequent file mark.
  296.          */
  297.         status = skipFiles(1);
  298.         if (status != SUCCESS) {
  299.         fatal("Can't skip over last filemark\n");
  300.         }
  301.     }
  302.     }
  303.     getDumpDate();
  304.     forkOffTar();
  305.     dumpDirectory(directoryToDump);
  306.     flushOutput();
  307.     waitForChildToDie();
  308.     openArchiveFile();
  309.     if (fatalErrors) {
  310.     sendMail("Dump failed with fatal errors");
  311.     } else {
  312.     if (nonFatalErrors) {
  313.         sendMail("Dump completed with non-fatal errors.");
  314.     } else {
  315.         sendMail("Dump completed successfully.");
  316.     }
  317.     recordTime();
  318.     }
  319.     debugp((stderr, "finished dumping %s, %.1lf MBytes\n",
  320.         directoryToDump, (double) totalBytes / (double) MBytes(1)));
  321. #else /* PROG_DUMP */
  322.     assert(progArgc >= 2);
  323.     if (fileNumber == 0) {
  324.     setFileNumber();
  325.     } else {
  326.     findLastFile();
  327.     }
  328.     skipOverFiles();
  329.     forkOffTar();
  330.     waitForChildToDie();
  331.     openArchiveFile();
  332.     rewindTape();
  333. #endif /* PROG_DUMP */
  334.     debugp((stderr,
  335.     "%s exiting, there were %d non-fatal errors, %d hard errors\n",
  336.     argv[0], nonFatalErrors, fatalErrors));
  337.     exit(fatalErrors);
  338. }
  339.  
  340. /*
  341.  *----------------------------------------------------------------------
  342.  *
  343.  * dumpDirectory --
  344.  *
  345.  *      Procedure to dump a directory tree.  This routine does an
  346.  *      inorder traversal of a directory.  It calls itself recursively
  347.  *      to dump each subdirectory.
  348.  *
  349.  * Results:
  350.  *      None.
  351.  * 
  352.  * Side effects:
  353.  *      Depends on the options, but normally the files in the specified
  354.  *      directory are dumped.
  355.  *  
  356.  *----------------------------------------------------------------------
  357.  */ 
  358.  
  359. static void
  360. dumpDirectory(dir)
  361.     char *dir;
  362. {
  363.     char pathname[MAXPATHLEN];
  364.     char backslash_pathname[MAXPATHLEN];
  365.     DIR *dirDesc;
  366.     struct direct *d;
  367.     int slash;
  368.  
  369.     if ((dirDesc = opendir(dir)) == NULL) {
  370.     warning("Cannot open directory `%s'", dir);
  371.     ++nonFatalErrors;
  372.     return;
  373.     }
  374.     slash =  (dir[strlen(dir) - 1] == '/');
  375.     while ((d = readdir(dirDesc)) != NULL) {
  376.     struct stat statBuf;
  377.  
  378.     if (*d->d_name == '.') {
  379.         if (d->d_name[1] == 0)
  380.         continue;
  381.         if (d->d_name[1] == '.' && d->d_name[2] == 0)
  382.         continue;
  383.     }
  384.     (void) sprintf(pathname, slash ? "%s%s" : "%s/%s", dir, d->d_name);
  385.     if (lstat(pathname, &statBuf)) {
  386.         warning("can't lstat %s", pathname);
  387.         ++nonFatalErrors;
  388.         continue;
  389.     }
  390.     quote_string(backslash_pathname, pathname);
  391.     if (statBuf.st_mtime >= lastTime || statBuf.st_ctime >= lastTime) {
  392.         if (puts(backslash_pathname) == EOF) {
  393.         (void) fprintf(stderr, "error in puts\n");
  394.         ++fatalErrors;
  395.         } else if (verbose) {
  396.         fprintf(stderr, "dumping %s\n", backslash_pathname);
  397.         }
  398.         totalBytes += statBuf.st_size;
  399.     }
  400.     if (((statBuf.st_mode & S_IFDIR) == S_IFDIR) && 
  401.         ((statBuf.st_mode & S_IFRLNK) != S_IFRLNK) &&
  402.         ((statBuf.st_mode & S_IFPDEV) != S_IFPDEV)) {
  403.         dumpDirectory(pathname);
  404.     }
  405.     }
  406.     (void) closedir(dirDesc);
  407.     return;
  408. }
  409.  
  410. static struct {
  411.     int     tape;
  412.     int     file;
  413.     int     level;
  414.     double  mbytes;
  415.     double  remaining;
  416.     double  errorRate;
  417.     time_t  time;
  418.     char    dirname[MAXPATHLEN];
  419. } dumpDateEntry;
  420.  
  421. #ifdef PROG_DUMP
  422. /*
  423.  *----------------------------------------------------------------------
  424.  *
  425.  * recordTime --
  426.  *
  427.  *    Append the start time of the current dump to the dump database.
  428.  *
  429.  * Results:
  430.  *      None.    
  431.  * 
  432.  * Side effects:
  433.  *      The start time of the current dump is appended to the end
  434.  *      of the dump database.  A fatal error occurs if the database
  435.  *      doesn't exist or is unwritable.
  436.  *      
  437.  *----------------------------------------------------------------------
  438.  */ 
  439.  
  440. static void
  441. recordTime()
  442. {
  443.     FILE         *fp = NULL;
  444.     char         *date;
  445.     Dev_TapeStatus    tapeStatus;
  446.     int            errors;
  447.     double        mbytes;
  448.     double        errorRate;
  449.     ReturnStatus    status = FAILURE;
  450.     double        remaining;
  451.     double        mbytesPerBlock;
  452.     char        *name = "UNKNOWN"; 
  453.     char        *serial = "UNKNOWN";
  454.     int            blocks;
  455.     char        shortDate[16];
  456.     char         buf[128];
  457.  
  458.     if (official) {
  459.     if ((fp = fopen(DUMPDATES, "a")) == NULL) {
  460.         fatal("Can't open %s", DUMPDATES);
  461.     }
  462.     }
  463.     date = asctime(localtime(&startTime));
  464.     date[24] = '\0';
  465.     mbytes = ((double) totalBytes) / ((double) MBytes(1));
  466.     debugp((stderr, "mbytes = %lf\n", mbytes));
  467.     errorRate = -1;
  468.     remaining = -1;
  469.     if (!oldFormat) {
  470.     bzero((char *) &tapeStatus, sizeof(tapeStatus));
  471.     debugp((stderr, "Getting tape status\n"));
  472.     status = Fs_IOControl(archivefd, IOC_TAPE_STATUS, 0, NULL, 
  473.         sizeof(tapeStatus), &tapeStatus);
  474.     if (status == SUCCESS) {
  475.         mbytesPerBlock = 
  476.         (double) tapeStatus.blockSize / (double) MBytes(1);
  477.         debugp((stderr, "position = %d, remaining = %d\n",
  478.             tapeStatus.position, tapeStatus.remaining));
  479.         blocks = tapeStatus.position - tapePosition;
  480.         mbytes = blocks * mbytesPerBlock;
  481.         errors = tapeStatus.readWriteRetry + tapeStatus.dataError;
  482.         errorRate = ((double) errors / (double) blocks) * 100.0;
  483.         remaining = tapeStatus.remaining * mbytesPerBlock;
  484.         debugp((stderr, 
  485.         "mbytes = %lf,  errorRate = %lf, remaining = %lf\n",
  486.         mbytes, errorRate, remaining));
  487.     }
  488.     }
  489.     (void) sprintf(buf, "%03d %03d %d %6.1lf %6.1lf %s  %s\n",
  490.            tapeNumber, fileNumber, dumpLevel, mbytes, remaining,
  491.            date, directoryToDump);
  492.     if (archiveFileIsATapeDrive) {
  493.     strcat(tapeBuffer, buf);
  494.     writeTapeLabel();
  495.     if (close(archivefd) != 0) {
  496.         fatal("Close of archive failed");
  497.     }
  498.     }
  499.     if (official) {
  500.     fprintf(fp, "%s", buf);
  501.     (void) fclose(fp);
  502.     }
  503.  
  504.     if ((fp = fopen(DRIVELOG, "a")) == NULL) {
  505.     fatal("Can't open %s", DRIVELOG);
  506.     }
  507.     if (status == SUCCESS) {
  508.     switch(tapeStatus.type) {
  509.         case DEV_TAPE_EXB8200:
  510.         name = "EXB-8200";
  511.         break;
  512.         case DEV_TAPE_EXB8500:
  513.         name = "EXB-8500";
  514.         break;
  515.         case DEV_TAPE_TLZ04:
  516.         name = "DEC-TLZ04";
  517.         break;
  518.         default: {
  519.         if (tapeStatus.type & DEV_TAPE_8MM) {
  520.             name = "UNKNOWN-8MM";
  521.         } else if (tapeStatus.type & DEV_TAPE_4MM) {
  522.             name = "UNKNOWN-4MM";
  523.         }
  524.         }
  525.     }
  526.     if (tapeStatus.serial[0] != '\0') {
  527.         serial = tapeStatus.serial;
  528.     }
  529.     }
  530.     bcopy(&date[4], shortDate, 7);
  531.     bcopy(&date[20], &shortDate[7], 4);
  532.     shortDate[11] = '\0';
  533.     fprintf(fp, "%-10s %-10s %3d %7.1lf %5.1lf%% %s %s\n", name, serial,
  534.     tapeNumber, mbytes, errorRate, shortDate, archiveFileName);
  535.     (void) fclose(fp);
  536.  
  537.     return;
  538. }
  539.  
  540. /*
  541.  *----------------------------------------------------------------------
  542.  *
  543.  * getNextDumpDateEntry --
  544.  *
  545.  *    Reads the next entry from the dump database file,
  546.  *    and puts the information into a structure.
  547.  *
  548.  * Results:
  549.  *    Returns non-zero if the next entry is read successfully.
  550.  * 
  551.  * Side effects:
  552.  *      A fatal error occurs if the database doesn't exist, is unreadable
  553.  *      or if it is improperly formated.
  554.  *      
  555.  *----------------------------------------------------------------------
  556.  */ 
  557. static int
  558. getNextDumpDateEntry()
  559. {
  560.     static FILE *fp;
  561.     static int lineCnt;
  562.     char buf[0x1000];
  563.     char *s;
  564.  
  565.     if (fp == NULL) {
  566.     if ((fp = fopen(DUMPDATES, "r")) == NULL) {
  567.         fatal("Can't open %s", DUMPDATES);
  568.     }
  569.     }
  570.  
  571.     /*
  572.      * read in the file line by line until we get a valid entry.
  573.      */
  574.     while (fgets(buf, sizeof(buf), fp)) {
  575.     ++lineCnt;
  576.     /*
  577.      * If the line is empty, only white space, or is a
  578.      * comment, then throw it away and continue.
  579.      */
  580.     s = buf;
  581.     while (*s == ' ' || *s == '\t') {
  582.         ++s;
  583.     }
  584.     if (*s == '#' || *s == '\n' || *s == '\0') {
  585.         continue;
  586.     }
  587.     if (parseDumpInfo(s) == 0) {
  588.         fatal("format error in %s: line %d |%s|",
  589.         DUMPDATES, lineCnt, buf);
  590.     }
  591.     return 1;
  592.     }
  593.     (void) fclose(fp);
  594.     return 0;
  595. }
  596. #endif
  597.  
  598. static int
  599. parseDumpInfo(buf)
  600.     char *buf;
  601. {
  602.     extern time_t mktime();
  603.     static char months[][4] = {
  604.     "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  605.     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
  606.     };
  607.     struct tm tm;
  608.     char *s;
  609.     int i;
  610.     int n;
  611.     int    token = 1;
  612.  
  613.     bzero((char *) &dumpDateEntry, sizeof(dumpDateEntry));
  614.     /*
  615.      * The first token is the tape number
  616.      */
  617.     if ((s = strtok(buf, " \t\n")) == NULL || !isdigit(*s)) {
  618.     goto mismatch;
  619.     }
  620.     dumpDateEntry.tape = atoi(s);
  621.     token++;
  622.     /*
  623.      * The next token is the file number
  624.      */
  625.     if ((s = strtok(NULL, " \t\n")) == NULL || !isdigit(*s)) {
  626.     goto mismatch;
  627.     }
  628.     dumpDateEntry.file = atoi(s);
  629.     token++;
  630.  
  631.     /* 
  632.      * The next token should be a single digit in the range 0-9 that
  633.      * indicates the level of the dump.
  634.      */
  635.     s = strtok((char *) NULL, " \t\n");
  636.     if (s == NULL || !isdigit(*s) || strlen(s) != 1) {
  637.     goto mismatch;
  638.     }
  639.     dumpDateEntry.level = *s - '0';
  640.     token++;
  641.  
  642.     /* the next token should be the number of bytes */
  643.     s = strtok((char *) NULL, " \t\n");
  644.     if (strchr(s, (int) '.')) {
  645.     /* Number of MBytes. */
  646.     n = sscanf(s, "%lf", &dumpDateEntry.mbytes);
  647.     if (n != 1) {
  648.         goto mismatch;
  649.     }
  650.     token++;
  651.     /* Number of remaining MBytes on tape. */
  652.     s = strtok((char *) NULL, " \t\n");
  653.     n = sscanf(s, "%lf", &dumpDateEntry.remaining);
  654.     if (n != 1) {
  655.         goto mismatch;
  656.     }
  657.     token++;
  658.     } else {
  659.     n = sscanf(s, "%d", &i);
  660.     if (n != 1) {
  661.         goto mismatch;
  662.     }
  663.     }
  664.     /*
  665.      * The time should be formated just like the return string
  666.      * from asctime(3).  So, parse the string and make sure the
  667.      * format is correct.
  668.      */
  669.  
  670.     if ((s = strtok((char *) NULL, " \t")) == NULL) {
  671.     goto mismatch;
  672.     }
  673.     token++;
  674.     if ((s  = strtok((char *) NULL, " ")) == NULL) {
  675.     goto mismatch;
  676.     }
  677.     token++;
  678.     for (i = 13; --i >= 0;) {
  679.     if (strcmp(months[i], s) == 0) {
  680.         break;
  681.     }
  682.     }
  683.     if ((tm.tm_mon = i) < 0) {
  684.     goto mismatch;
  685.     }
  686.     if ((s = strtok((char *) NULL, " ")) == NULL) {
  687.     goto mismatch;
  688.     }
  689.     token++;
  690.     tm.tm_mday = atoi(s);
  691.     if ((s = strtok((char *) NULL, ":")) == NULL) {
  692.     goto mismatch;
  693.     }
  694.     token++;
  695.     tm.tm_hour = atoi(s);
  696.     if ((s = strtok((char *) NULL, ":")) == NULL) {
  697.     goto mismatch;
  698.     }
  699.     token++;
  700.     tm.tm_min = atoi(s);
  701.     if ((s = strtok((char *) NULL, " ")) == NULL) {
  702.     goto mismatch;
  703.     }
  704.     token++;
  705.     tm.tm_sec = atoi(s);
  706.     if ((s = strtok((char *) NULL, " \t\n")) == NULL) {
  707.     goto mismatch;
  708.     }
  709.     tm.tm_year = atoi(s) - 1900;
  710.     /* Convert to old-fashioned calander time */
  711.     if((dumpDateEntry.time = mktime(&tm)) == -1) {
  712.     debugp((stderr, "parseDumpInfo:  mktime failed\n"));
  713.     return 0;
  714.     }
  715.  
  716.     token++;
  717.     if ((s = strtok((char *) NULL, " \t\n")) == NULL) {
  718.     goto mismatch;
  719.     }
  720.  
  721.     /*
  722.      * The remainder of the line is the directory name.
  723.      */
  724.     strcpy(dumpDateEntry.dirname, s);
  725.     return 1;
  726. mismatch:
  727.     debugp((stderr, "parseDumpInfo:  parse error on token %d \"%s\"\n", 
  728.         token, s));
  729.     return 0;
  730.  
  731. }
  732.  
  733.  
  734. #ifdef PROG_DUMP
  735. /*
  736.  *----------------------------------------------------------------------
  737.  *
  738.  * getDumpDate --
  739.  *
  740.  *    Reads the dump database file, and determines the last time
  741.  *      that a lower level dump of the directory was done.
  742.  *
  743.  * Results:
  744.  *    Returns the time of the last lower level dump.
  745.  * 
  746.  * Side effects:
  747.  *      A fatal error occurs if the database doesn't exist, is unreadable
  748.  *      or if it is improperly formated.
  749.  *      
  750.  *----------------------------------------------------------------------
  751.  */ 
  752.  
  753. static void
  754. getDumpDate()
  755. {
  756.     time_t t = 0;
  757.  
  758.     while (getNextDumpDateEntry()) {
  759.     if (strcmp(dumpDateEntry.dirname, directoryToDump) != 0) {
  760.         continue;
  761.     }
  762.     if (dumpDateEntry.level < dumpLevel) {
  763.         t = dumpDateEntry.time;
  764.     }
  765.     }
  766.     lastTime = t;
  767.     return;
  768. }
  769. #endif
  770.  
  771. /*
  772.  *----------------------------------------------------------------------
  773.  *
  774.  * openArchiveFile --
  775.  *
  776.  *    Opens the archive file and checks to see if it is a tapedrive.
  777.  *
  778.  * Results:
  779.  *    None
  780.  * 
  781.  * Side effects:
  782.  *      Opens the archive file.
  783.  *      
  784.  *----------------------------------------------------------------------
  785.  */ 
  786.  
  787. static void
  788. openArchiveFile()
  789. {
  790.     struct stat statBuf;
  791.     extern int Fs_GetAttributes();
  792.     Fs_Attributes attrs;
  793.     Dev_TapeStatus    tapeStatus;
  794.     ReturnStatus    status;
  795.  
  796.     debugp((stderr, "opening %s as archive file\n", archiveFileName));
  797. #ifdef PROG_DUMP
  798.     if (strcmp(archiveFileName, "-") == 0) {
  799.     archivefd = 1;
  800.     } else if ((archivefd = open(archiveFileName,O_RDWR)) < 0) {
  801.     if ((archivefd = open(archiveFileName,
  802.                   O_RDWR|O_CREAT, 0664)) < 0) {
  803.         fatal("Can't open `%s'", archiveFileName);
  804.     }
  805.     }
  806. #else    
  807.     if (strcmp(archiveFileName, "-") == 0) {
  808.     archivefd = 0;
  809.     } else if ((archivefd = open(archiveFileName,O_RDONLY)) < 0) {
  810.     fatal("Can't open `%s'", archiveFileName);
  811.     }
  812. #endif
  813.     if (fstat(archivefd, &statBuf)) {
  814.     fatal("Cannot stat %s", archiveFileName);
  815.     }
  816.     switch (statBuf.st_mode & S_IFMT) {
  817.  
  818.     case S_IFREG:        /* regular file */
  819.         break;
  820.  
  821.     case S_IFCHR:        /* character dev. -- probably a tape drive */
  822.     if (Fs_GetAttributes(archiveFileName, 0, &attrs) != SUCCESS) {
  823.         fatal("Cannot get attributes of %s", archiveFileName);
  824.     }
  825.     if (attrs.devType == 5) {
  826.         archiveFileIsATapeDrive = TRUE;
  827.         bzero((char *) &tapeStatus, sizeof(tapeStatus));
  828.         status = Fs_IOControl(archivefd, IOC_TAPE_STATUS, 0, NULL, 
  829.         sizeof(tapeStatus), &tapeStatus);
  830.         debugp((stderr, "IOC_TAPE_STATUS returned 0x%x\n", status));
  831.         if (status != SUCCESS) {
  832.         oldFormat = TRUE;
  833.         debugp((stderr, "Using old format.\n", status));
  834.         } else {
  835.         debugp((stderr, "tapeStatus.type is 0x%x\n", tapeStatus.type));
  836.         if (tapeStatus.type == DEV_TAPE_EXB8200) {
  837.             oldFormat = TRUE;
  838.             debugp((stderr, "Using old format.\n", status));
  839.         }
  840.  
  841. #ifndef PROG_DUMP
  842.         if ((tapeStatus.type == DEV_TAPE_EXB8500) &&
  843.            (tapeStatus.density == DEV_EXB8500_8200_MODE)) {
  844.             oldFormat = TRUE;
  845.             debugp((stderr, "Using old format.\n", status));
  846.         }
  847. #endif
  848.         }
  849.         break;
  850.     }
  851.     /* FALLTHROUGH */
  852.     default:
  853.     warning("%s: not a normal file or tape drive", archiveFileName);
  854.     break;
  855.     }
  856.     return;
  857. }
  858.  
  859. /*
  860.  *----------------------------------------------------------------------
  861.  *
  862.  * forkOffTar --
  863.  *
  864.  *    Forks off tar and pipes stdout into it.
  865.  *
  866.  * Results:
  867.  *    None
  868.  * 
  869.  * Side effects:
  870.  *      Creates a child process.
  871.  *      
  872.  *----------------------------------------------------------------------
  873.  */ 
  874. static void
  875. forkOffTar()
  876. {
  877.     char         tarargs[20];
  878.     char         blocks[20];
  879.     Dev_TapeStatus    tapeStatus;
  880.     ReturnStatus    status;
  881. #ifdef PROG_RESTORE
  882.     char **arg;
  883.     int i, j;
  884. #endif
  885.  
  886.     if (!oldFormat) {
  887.     bzero((char *) &tapeStatus, sizeof(tapeStatus));
  888.     status = Fs_IOControl(archivefd, IOC_TAPE_STATUS, 0, NULL, 
  889.         sizeof(tapeStatus), &tapeStatus);
  890.     if (status != SUCCESS) {
  891.         debugp((stderr, "IOC_TAPE_STATUS returned 0x%x\n", status));
  892.     } else {
  893.         tapePosition = tapeStatus.position;
  894.         debugp((stderr, "position = %d\n", tapePosition));
  895.     }
  896.     }
  897. #ifdef PROG_DUMP    
  898.  
  899.     if (pipe(pipefd) < 0) {
  900.     fatal("Cannot open pipe");
  901.     }
  902.     switch (tarChild = fork()) {
  903.  
  904.     case -1:
  905.     fatal("Can't fork");
  906.  
  907.     case 0:
  908.     (void) close(pipefd[1]);
  909.     if (dup2(archivefd, 1) < 0) {
  910.         fatal("dup2");
  911.     }
  912.     if (dup2(pipefd[0], 0) < 0) {
  913.         fatal("dup2");
  914.     }
  915.     *tarargs = '\0';
  916.     if (resetAccessTimes) {
  917.         strcat(tarargs, "a");
  918.     }
  919.     if (verbose) {
  920.         strcat(tarargs, "v");
  921.     }
  922.     if (debug) {
  923.         strcat(tarargs, "e");
  924.     }
  925.     if (oldFormat) {
  926.         strcat(tarargs, "ncfTPL");
  927.         debugp((stderr, "execing tar %s - -\n", tarargs));
  928.         execlp(TAR, TAR, tarargs, "-", "-", NULL);
  929.     } else {
  930.         strcat(tarargs, "ncbfTPL");
  931.         sprintf(blocks, "%d", tarBlocks);
  932.         debugp((stderr, "execing tar %s %s - -\n", tarargs, blocks));
  933.         execlp(TAR, TAR, tarargs, blocks, "-", "-", NULL);
  934.     }
  935.     fatal("exec failed");
  936.  
  937.     default:
  938.     (void) close(pipefd[0]);
  939.     if (dup2(pipefd[1], 1)) {
  940.         fatal("dup2");
  941.     }
  942.     }
  943. #else
  944.  
  945.     sprintf(blocks, "%d", tarBlocks);
  946.     close(archivefd);
  947.     switch (tarChild = fork()) {
  948.  
  949.     case -1:
  950.     fatal("Can't fork");
  951.  
  952.     case 0: {
  953.     char **ptr;
  954.     arg = (char **) malloc(sizeof(char **) * (progArgc + 5));
  955.     ptr = arg;
  956.     *ptr++ = TAR;
  957.     if (printContents) {
  958.         strcpy(tarargs, "tv");
  959.     } else {
  960.         strcpy(tarargs, "x");
  961.     }
  962.     if (oldFormat) {
  963.         strcat(tarargs, "pf");
  964.     } else {
  965.         strcat(tarargs, "pfb");
  966.     }
  967.     if (verbose) {
  968.         strcat(tarargs, "v");
  969.     }
  970.     if (!relativePaths) {
  971.         strcat(tarargs, "P");
  972.     }
  973.     if (debug) {
  974.         strcat(tarargs, "e");
  975.     }
  976.     *ptr++ = tarargs;
  977.     *ptr++ = archiveFileName;
  978.     if (!oldFormat) {
  979.         *ptr++ = blocks;
  980.     }
  981.     for (i = 1; (*ptr++ = progArgv[i]) != NULL; ++i) {
  982.         continue;
  983.     }
  984.     debugp((stderr, "execing tar"));
  985.     for (j = 0; j < i + 3; j++) {
  986.         debugp((stderr, " %s", arg[j]));
  987.     }
  988.     debugp((stderr, "\n"));
  989.     execvp(TAR, arg);
  990.     fatal("exec failed");
  991.     }
  992.     default:
  993.     break;
  994.     }
  995. #endif    
  996.     debugp((stderr, "successfully forked tar\n"));
  997.     return;
  998. }
  999.  
  1000. #ifdef PROG_DUMP
  1001. /*
  1002.  *----------------------------------------------------------------------
  1003.  *
  1004.  * flushOutput --
  1005.  *
  1006.  *    Wait for tar to finish reading all the data in the pipe.
  1007.  *    Check the error return code.
  1008.  *
  1009.  * Results:
  1010.  *    None
  1011.  * 
  1012.  * Side effects:
  1013.  *      Closes files, increments a global variable.
  1014.  *      
  1015.  *----------------------------------------------------------------------
  1016.  */ 
  1017. static void
  1018. flushOutput()
  1019. {
  1020.  
  1021.     debugp((stderr, "flushing output\n"));
  1022.     (void) fflush(stdout);
  1023.     (void) close(1);
  1024.     (void) close(pipefd[1]);
  1025.     return;
  1026. }
  1027. #endif
  1028.  
  1029. static void
  1030. waitForChildToDie()
  1031. {
  1032.     int w;
  1033.     union wait ws;
  1034.  
  1035.     while ((w = wait(&ws)) > 0 && w != tarChild) {
  1036.     continue;
  1037.     }
  1038.     switch (ws.w_retcode) {
  1039.  
  1040.     case 0:     /* normal exit */
  1041.     break;
  1042.  
  1043.     case 1:
  1044.         fatal("tar invoked with invalid arguments");
  1045.     break;
  1046.  
  1047.     case 2:
  1048.     warning("tar encountered at least one invalid filename");
  1049.     ++nonFatalErrors;
  1050.     break;
  1051.  
  1052.     case 3:
  1053.     fatal("bad archive");
  1054.     break;
  1055.  
  1056.     case 4:
  1057.     fatal("system error in tar");
  1058.     break;
  1059.  
  1060.     default:
  1061.     fatal("tar exited with nozero status: %d", ws.w_retcode);
  1062.     break;
  1063.     }
  1064.     (void) close(archivefd);
  1065.     return;
  1066. }
  1067.  
  1068. /*
  1069.  *----------------------------------------------------------------------
  1070.  *
  1071.  * readTapeLabel --
  1072.  *
  1073.  *    Read the label on a tape, and put the label into the tapeBuffer.
  1074.  *
  1075.  * Results:
  1076.  *    None
  1077.  * 
  1078.  * Side effects:
  1079.  *      The tape is rewound.
  1080.  *      
  1081.  *----------------------------------------------------------------------
  1082.  */
  1083.  
  1084. static void
  1085. readTapeLabel()
  1086. {
  1087.     ReturnStatus    status = SUCCESS;
  1088.     int            n;
  1089.     int            bytesRead;
  1090.     Dev_TapeStatus    tapeStatus;
  1091.  
  1092.     debugp((stderr, "reading tape label\n"));
  1093.     labelSize = LABEL_SIZE_OLD;
  1094.     bzero((char *) &tapeStatus, sizeof(tapeStatus));
  1095.     status = Fs_IOControl(archivefd, IOC_TAPE_STATUS, 0, NULL, 
  1096.     sizeof(tapeStatus), &tapeStatus);
  1097.     if ((status != SUCCESS) || (tapeStatus.type == DEV_TAPE_EXB8200) ||
  1098.     (reInitialize) || (reInitializeSafe)) {
  1099.     /*
  1100.      * The tape may be in the old format if the tape drive is an
  1101.      * exb8200, or if we are reinitializing an old format tape.
  1102.      * Try reading the label at the beginning of the tape.
  1103.      */
  1104.     rewindTape();
  1105.     
  1106.     bytesRead = read(archivefd, tapeBuffer, labelSize);
  1107.     debugp((stderr, "attempt to read old label read %d bytes\n", 
  1108.             bytesRead));
  1109.     if (bytesRead == labelSize) { 
  1110.         if (!strncmp(tapeBuffer, SPRITE_OLD_DUMP_HEADER, 
  1111.             strlen(SPRITE_OLD_DUMP_HEADER)) != 0) {
  1112.         oldFormat = TRUE;
  1113.         debugp((stderr, "Using old format\n"));
  1114.         n = sscanf(tapeBuffer + strlen(SPRITE_OLD_DUMP_HEADER), 
  1115.             "%d", &tapeNumber);
  1116.         if (n != 1) {
  1117.             warning("Couldn't read tape number from label\n");
  1118.         }
  1119.         } else if (oldFormat) {
  1120.         fatal("The tape does not have a correct label");
  1121.         }
  1122.     }
  1123.     }
  1124.     if (!oldFormat) {
  1125.     Boolean    beginning = FALSE;
  1126.  
  1127.     labelSize = LABEL_SIZE;
  1128.     gotoEOD();
  1129.     /*
  1130.      * Keep backing up one file at a time until we find a label, or
  1131.      * the beginning of the tape. In order to back up one file at
  1132.      * a time we must back up over both the current file and the 
  1133.      * previous file, hence the skip backwards over two files.
  1134.      * 
  1135.      */
  1136.     status = SUCCESS;
  1137.     while(status == SUCCESS) {
  1138.         status = skipFiles(-2);
  1139.         if (status == DEV_END_OF_TAPE) {
  1140.         /*
  1141.          * We must have hit the beginning of the tape.
  1142.          * Keep track so we only do this once.
  1143.          */
  1144.         debugp((stderr, "hit beginning of tape\n"));
  1145.         if (beginning == TRUE) {
  1146.             fatal("The tape does not have a correct label");
  1147.         }
  1148.         beginning = TRUE;
  1149.         status = SUCCESS;
  1150.         } else if (status == SUCCESS) {
  1151.         /*
  1152.          * We are now on the BOT side of a file mark. Skip to the
  1153.          * EOT side.
  1154.          */
  1155.         debugp((stderr, "skipping over file mark\n"));
  1156.         status = skipFiles(1);
  1157.         if (status != SUCCESS) {
  1158.             fatal("Error skipping over file mark");
  1159.         }
  1160.         }
  1161.         /*
  1162.          * Try reading the label. 
  1163.          */
  1164.         debugp((stderr, "trying to read label (%d bytes)\n",
  1165.         labelSize));
  1166.         bytesRead = read(archivefd, tapeBuffer, labelSize);
  1167.         if (bytesRead == labelSize) { 
  1168.         debugp((stderr, "read succeeded\n"));
  1169.         if (!strncmp(tapeBuffer, SPRITE_DUMP_HEADER, 
  1170.             strlen(SPRITE_DUMP_HEADER))){
  1171.             /* 
  1172.              * We found a label.
  1173.              */
  1174.             debugp((stderr, "found a label\n"));
  1175.             break;
  1176.         } else {
  1177.             debugp((stderr, "found \"%s\"\n", tapeBuffer));
  1178.         }
  1179.         } else {
  1180.         debugp((stderr, "only read %d bytes\n", bytesRead));
  1181.         }
  1182.     }
  1183.     if (status != SUCCESS) {
  1184.         fatal("The tape does not have a correct label");
  1185.     }
  1186.     n = sscanf(tapeBuffer + strlen(SPRITE_DUMP_HEADER), 
  1187.         "%*s %d %*s %d %*s %d\n", &version, &tapeLevel, 
  1188.             &tapeNumber);
  1189.     if (n != 3) {
  1190.         fatal("Couldn't read information from tape label\n");
  1191.     }
  1192.     if (version != SPRITE_DUMP_VERSION) { 
  1193.         fatal("Invalid dump tape version \"%d\"\n", version);
  1194.     }
  1195.     }
  1196.     debugp((stderr, "Tape: %d\n", tapeNumber));
  1197.     debugp((stderr, "Version: %d\n", version));
  1198.     debugp((stderr, "Level: %d\n", tapeLevel));
  1199.     debugp((stderr, "TapeLabel=|%s|\n", tapeBuffer));
  1200.     return;
  1201. }
  1202.  
  1203. #ifdef PROG_DUMP
  1204. /*
  1205.  *----------------------------------------------------------------------
  1206.  *
  1207.  * writeTapeLabel --
  1208.  *
  1209.  *    Copy the tapeBuffer onto the tape.
  1210.  *
  1211.  * Results:
  1212.  *    None
  1213.  * 
  1214.  * Side effects:
  1215.  *      The tape is rewound.
  1216.  *      
  1217.  *----------------------------------------------------------------------
  1218.  */
  1219.  
  1220. static void
  1221. writeTapeLabel()
  1222. {
  1223.  
  1224.     debugp((stderr, "writing tape label\n"));
  1225.     if (oldFormat) {
  1226.     rewindTape();
  1227.     } else {
  1228.     gotoEOD();
  1229.     }
  1230.     if (write(archivefd, tapeBuffer, labelSize) != labelSize) {
  1231.     fatal("Error writing tape label");
  1232.     }
  1233.     /*
  1234.      * Rewinding the tape prevents a file mark from being written, which
  1235.      * is what we want on the old format tapes.
  1236.      */
  1237.     if (oldFormat) {
  1238.     rewindTape();
  1239.     }
  1240.     return;
  1241. }
  1242. #endif
  1243.  
  1244. static void
  1245. initializeTape()
  1246. {   
  1247.     int nbufs;
  1248.     FILE *fp;
  1249.     Dev_TapeStatus    tapeStatus;
  1250.     int            tocSize;
  1251.     static char        tempBuffer[IOBUF_SIZE];
  1252.     ReturnStatus    status;
  1253.  
  1254.     debugp((stderr, "initializing tape #%d\n", tapeNumber));
  1255.     if (archiveFileIsATapeDrive == 0) {
  1256.     fatal("Cannot initialize:  Archive file is not a tape drive");
  1257.     }
  1258.     rewindTape();
  1259.     bzero((char *) &tapeStatus, sizeof(tapeStatus));
  1260.     status = Fs_IOControl(archivefd, IOC_TAPE_STATUS, 0, NULL, 
  1261.     sizeof(tapeStatus), &tapeStatus);
  1262.     if ((status != SUCCESS) || (tapeStatus.type == DEV_TAPE_EXB8200)) {
  1263.     oldFormat = TRUE;
  1264.     labelSize = LABEL_SIZE_OLD;
  1265.     } else {
  1266.     oldFormat = FALSE;
  1267.     labelSize = LABEL_SIZE;
  1268.     }
  1269.     memset(tapeBuffer, '\0', labelSize);
  1270.     if (oldFormat) {
  1271.     sprintf(tapeBuffer, "%s%d\n", SPRITE_OLD_DUMP_HEADER, tapeNumber);
  1272.     } else {
  1273.     char    format[80];
  1274.     strcpy(format, SPRITE_DUMP_HEADER);
  1275.     strcat(format, SPRITE_DUMP_INFO);
  1276.     sprintf(tapeBuffer, format, SPRITE_DUMP_VERSION, tapeLevel,tapeNumber);
  1277.     strcat(tapeBuffer, "\n");
  1278.     }
  1279.  
  1280.     debugp((stderr, "writing label\n"));
  1281.     if (write(archivefd, tapeBuffer, labelSize) != labelSize) {
  1282.     fatal("Write error while initializing tape label");
  1283.     }
  1284.     debugp((stderr, "done writing label\n"));
  1285.     if (oldFormat) {
  1286.     tocSize = TOC_SIZE_OLD;
  1287.     } else {
  1288.     tocSize = TOC_SIZE;
  1289.     }
  1290.     debugp((stderr, "writing padding\n"));
  1291.     memset(tempBuffer, '\0', sizeof(tempBuffer));
  1292.     for (nbufs = tocSize / IOBUF_SIZE; --nbufs > 0;) {
  1293.     if (write(archivefd, tempBuffer,
  1294.           sizeof(tempBuffer)) != sizeof(tempBuffer)) {
  1295.         fatal("Write error while initializing tape label");
  1296.     }
  1297.     }
  1298.     debugp((stderr, "done writing padding\n"));
  1299.     if (!oldFormat) {
  1300.     Dev_TapeCommand args;
  1301.     args.command = IOC_TAPE_WEOF;
  1302.     args.count = 1;
  1303.     status = Fs_IOControl(archivefd, IOC_TAPE_COMMAND, sizeof(args),
  1304.             (Address)&args, 0, (Address) 0);
  1305.     if (status != SUCCESS) {
  1306.         fatal("Can't write file mark(s), status = 0x%x", status);
  1307.         exit(status);
  1308.     }
  1309.     }
  1310.     rewindTape();
  1311.     if (official) {
  1312.     if ((fp = fopen(DUMPDATES, "a")) == NULL) {
  1313.         fatal("Can't open %s", DUMPDATES);
  1314.     }
  1315.     /*
  1316.      *   Put a comment in the dump data file.
  1317.      */
  1318.     fprintf(fp, "# Initializing tape number %03d\n", tapeNumber);
  1319.     (void) fclose(fp);
  1320.     }
  1321.     return;
  1322. }
  1323.  
  1324. static void
  1325. rewindTape()
  1326. {
  1327.     int oldOffset;
  1328.     int status;
  1329.  
  1330.     debugp((stderr, "rewinding tape ...\n"));
  1331.     status = Ioc_Reposition(archivefd, IOC_BASE_ZERO, 0, &oldOffset);
  1332.     if (status != SUCCESS) {
  1333.     fatal("Can't rewind tape drive, status = 0x%08x", status);
  1334.     }
  1335.     debugp((stderr, "done rewinding tape.\n"));
  1336.     return;
  1337. }
  1338.  
  1339. static void
  1340. setFileNumber()
  1341. {
  1342.     char *s;
  1343. #ifdef PROG_DUMP
  1344.     fileNumber = 1;
  1345.     for (s = tapeBuffer; *s != '\0'; ++s) {
  1346.     if (s[0] == '\n' && s[1] > ' ') {
  1347.         ++fileNumber;
  1348.     }
  1349.     }
  1350. #else
  1351.     char *end;
  1352.     int len = 0;
  1353.     int n = 1;
  1354.  
  1355.     /*
  1356.      * Check each file on the dumptape, and pick the one that is the
  1357.      * longest prefix of the file to be restored.
  1358.      */
  1359.  
  1360.     if ((end = strchr(tapeBuffer, '\n')) == NULL) {
  1361.     fatal("Bad tape label\n");
  1362.     }
  1363.     for (s = end; *s != '\0'; ++n) {
  1364.     s = end + 1;
  1365.     if ((end = strchr(s, '\n')) == NULL) {
  1366.         break;
  1367.     }
  1368.     *end = '\0';
  1369.     if (parseDumpInfo(s) == 0) {
  1370.         fatal("format error in tapelabel, line %d\n", n);
  1371.     }
  1372.     assert(dumpDateEntry.file == n);
  1373.     lastFile = n;
  1374.     if (strlen(dumpDateEntry.dirname) >= len) {
  1375.         if (strncmp(dumpDateEntry.dirname, progArgv[1],
  1376.                 strlen(dumpDateEntry.dirname)) == 0) {
  1377.                 len = strlen(dumpDateEntry.dirname);
  1378.         fileNumber = n;
  1379.             }
  1380. #if 0        
  1381.         else if (dumpDateEntry.dirname[0] == '/') {
  1382.         if (strncmp(dumpDateEntry.dirname + 1, progArgv[1],
  1383.                     strlen(dumpDateEntry.dirname) - 1) == 0) {
  1384.             len = strlen(dumpDateEntry.dirname) - 1;
  1385.             fileNumber = n;
  1386.                 }
  1387.         }
  1388. #endif        
  1389.     }
  1390.     }
  1391.     (void) fprintf(stderr, "Using file #%d\n", fileNumber);
  1392.     if (fileNumber == 0) {
  1393.     fatal("None of the files on this tape contain %s.\n", progArgv[1]);
  1394.     }
  1395. #endif    
  1396.     return;
  1397. }
  1398.  
  1399. #ifdef PROG_RESTORE
  1400. static void
  1401. findLastFile()
  1402. {
  1403.     char *s;
  1404.     int n = 1;
  1405.     char *end;
  1406.  
  1407.     if ((end = strchr(tapeBuffer, '\n')) == NULL) {
  1408.     fatal("Bad tape label\n");
  1409.     }
  1410.     for (s = end; *s != '\0'; ++n) {
  1411.     s = end + 1;
  1412.     if ((end = strchr(s, '\n')) == NULL) {
  1413.         break;
  1414.     }
  1415.     *end = '\0';
  1416.     lastFile = n;
  1417.     }
  1418. }
  1419. #endif /* PROG_RESTORE */
  1420.  
  1421. static void
  1422. skipOverFiles()
  1423. {
  1424.     int         status;
  1425.     int             num;
  1426. #ifdef PROG_DUMP
  1427.     Dev_TapeCommand     args;
  1428. #endif
  1429.  
  1430.     assert(fileNumber);
  1431.     if (oldFormat) {
  1432.     rewindTape();
  1433.     num = fileNumber;
  1434.     } else {
  1435.     /*
  1436.      * In the new format we don't rewind the tape.  Instead we back
  1437.      * up from where we currently are to the file we want.
  1438.      */
  1439.     num = - (lastFile - fileNumber + 1) * 2;
  1440.     }
  1441.     status = skipFiles(num);
  1442.     if (status != SUCCESS) {
  1443.     fatal("Can't skip files, status = 0x%08x", status);
  1444.     }
  1445. #ifdef PROG_DUMP
  1446.     if (oldFormat) {
  1447.     debugp((stderr, "Backing up over filemark\n"));
  1448.     status = skipFiles(-1);
  1449.     if (status != SUCCESS) {
  1450.         fatal("Can't skip files, status = 0x%08x", status);
  1451.     }
  1452.     } 
  1453.     debugp((stderr, "rewriting file mark\n"));
  1454.     args.command = IOC_TAPE_WEOF;
  1455.     args.count = 1;
  1456.     status = Fs_IOControl(archivefd, IOC_TAPE_COMMAND, sizeof(args),
  1457.               (char *) &args, 0, (char *) 0);
  1458. #else
  1459.     if (!oldFormat) {
  1460.     /*
  1461.      * Since we backed up we are on the BOT side of a file mark.
  1462.      * Skip over it.
  1463.      */
  1464.     debugp((stderr, "Skipping over filemark\n"));
  1465.     status = skipFiles(1);
  1466.     if (status != SUCCESS) {
  1467.         fatal("Can't skip files, status = 0x%08x", status);
  1468.     }
  1469.     }
  1470. #endif
  1471.     debugp((stderr, "successfully skipped %d files\n", fileNumber));
  1472.     return;
  1473. }
  1474.  
  1475. /*ARGSUSED*/
  1476. static void
  1477. cleanup_sighup(sig)
  1478.     int sig;
  1479. {
  1480.  
  1481.     fatal("Received SIGHUP signal, terminating abnormally");
  1482.     return;
  1483. }
  1484.  
  1485. /*ARGSUSED*/
  1486. static void
  1487. cleanup_sigint(sig)
  1488.     int sig;
  1489. {
  1490.  
  1491.     fatal("Received SIGINT signal, terminating abnormally");
  1492.     return;
  1493. }
  1494.  
  1495. /*ARGSUSED*/
  1496. static void
  1497. cleanup_sigquit(sig)
  1498.     int sig;
  1499. {
  1500.  
  1501.     fatal("Received SIGQUIT signal, terminating abnormally");
  1502.     return;
  1503. }
  1504.  
  1505. /*ARGSUSED*/
  1506. static void
  1507. cleanup_sigpipe(sig)
  1508.     int sig;
  1509. {
  1510. #if 1
  1511. {
  1512.     int w;
  1513.     union wait ws;
  1514.  
  1515.     debugp((stderr, "Received SIGPIPE signal, terminating abnormally\n"));
  1516.     while ((w = wait(&ws)) > 0 && w != tarChild) {
  1517.     continue;
  1518.     }
  1519.     debugp((stderr, "SIGPIPE: tar exited with code = 0x%x\n", ws.w_retcode));
  1520.  
  1521.     if (ws.w_retcode) {
  1522.     warning("tar exited with nozero status: %d", ws.w_retcode);
  1523.     ++fatalErrors;
  1524.     }
  1525.     (void) close(archivefd);
  1526. }
  1527. #endif
  1528.  
  1529.     fatal("Received SIGPIPE signal, terminating abnormally");
  1530.     return;
  1531. }
  1532.  
  1533. /*ARGSUSED*/
  1534. static void
  1535. cleanup_sigterm(sig)
  1536.     int sig;
  1537. {
  1538.  
  1539.     fatal("Received SIGTERM signal, terminating abnormally");
  1540.     return;
  1541. }
  1542.  
  1543. /*
  1544.  *----------------------------------------------------------------------
  1545.  *
  1546.  * sendMail --
  1547.  *
  1548.  * Results:
  1549.  *    None.
  1550.  *
  1551.  * Side effects:
  1552.  *    Sends mail to the person specified by the -m option.
  1553.  *
  1554.  *----------------------------------------------------------------------
  1555.  */
  1556.  
  1557. static void
  1558. sendMail(msg)
  1559.     const char *msg;
  1560. {
  1561.     int p[2];
  1562.     int childPid;
  1563.     int w;
  1564.     FILE *fp;
  1565.  
  1566.     if (mailWho == NULL) {
  1567.     return;
  1568.     }
  1569.     pipe(p);
  1570.  
  1571.     fprintf(stderr, "sending mail to `%s'\n", mailWho);
  1572.  
  1573.     switch (childPid = fork()) {
  1574.  
  1575.     case -1:
  1576.     fatal("Fork failed");
  1577.  
  1578.     case 0: /* child */
  1579.     close(pipefd[1]);
  1580.     dup2(pipefd[0], 0);
  1581.     execlp("mail", "mail", mailWho, NULL);
  1582.     fatal("Can't exec `mail'");
  1583.     /* NOTREACHED */
  1584.  
  1585.     default: /* parent */
  1586.         close(pipefd[0]);
  1587.     fp = fdopen(pipefd[1], "w");
  1588.     fprintf(fp, "%s.\n\n", msg);
  1589.     fprintf(fp, "Level %d dump of %s on %s",
  1590.         dumpLevel, directoryToDump,
  1591.         asctime(localtime(&startTime)));
  1592.     (void) fclose(fp);
  1593.     while ((w = wait(0)) > 0 && w != childPid)
  1594.       ;
  1595.     fprintf(stderr, "done sending mail\n");
  1596.     break;
  1597.     }
  1598.     return;
  1599. }
  1600.  
  1601. /*
  1602.  *----------------------------------------------------------------------
  1603.  *
  1604.  * fatal --
  1605.  *
  1606.  *    Print an error message and terminate the program.
  1607.  *
  1608.  * Results:
  1609.  *    None.
  1610.  *
  1611.  * Side effects:
  1612.  *      A formated error message is printed to stderr, and
  1613.  *      the program is terminated.
  1614.  *
  1615.  *----------------------------------------------------------------------
  1616.  */
  1617.  
  1618. #ifndef lint
  1619. static void
  1620. fatal(va_alist)
  1621.     va_dcl
  1622. {
  1623.     char *errmsg;
  1624.     va_list args;
  1625.     char mailBuf[0x1000];
  1626.     char    *fmt;
  1627.  
  1628.     errmsg = strerror(errno);
  1629.     va_start(args);
  1630.     fmt = va_arg(args, char *);
  1631.     (void) fprintf(stderr, "Dump: ");
  1632.     (void) vfprintf(stderr, fmt, args);
  1633.     (void) fprintf(stderr, ": %s\n", errmsg);
  1634.     (void) fflush(stderr);
  1635.  
  1636.     (void) vsprintf(mailBuf, fmt, args);
  1637.     (void) strcat(mailBuf, ": ");
  1638.     (void) strcat(mailBuf, errmsg);
  1639.     sendMail(mailBuf);
  1640.  
  1641.     va_end(args);
  1642.     exit(1);
  1643. }
  1644. #else
  1645. /*VARARGS1*/
  1646. /*ARGSUSED*/
  1647. void
  1648. fatal(fmt)
  1649.     char *fmt;
  1650. {
  1651.     return;
  1652. }
  1653. #endif  /* !lint */
  1654.  
  1655.  
  1656. /*
  1657.  *----------------------------------------------------------------------
  1658.  *
  1659.  * warning --
  1660.  *
  1661.  *    Print a warning message.
  1662.  *
  1663.  * Results:
  1664.  *    None.
  1665.  *
  1666.  * Side effects:
  1667.  *      A formated error message is printed to stderr.
  1668.  *
  1669.  *----------------------------------------------------------------------
  1670.  */
  1671.  
  1672. #ifndef lint
  1673. static void
  1674. warning(va_alist)
  1675.     va_dcl
  1676. {
  1677.     const char *errmsg;
  1678.     va_list args;
  1679.     char    *fmt;
  1680.  
  1681.     errmsg = strerror(errno);
  1682.     va_start(args);
  1683.     fmt = va_arg(args, char *);
  1684.     (void) fprintf(stderr, "Dump: ");
  1685.     (void) vfprintf(stderr, fmt, args);
  1686.     (void) fprintf(stderr, ": %s\n", errmsg);
  1687.     (void) fflush(stderr);
  1688.     va_end(args);
  1689.     return;
  1690. }
  1691. #else
  1692. /*VARARGS1*/
  1693. /*ARGSUSED*/
  1694. void
  1695. warning(fmt)
  1696.     char *fmt;
  1697. {
  1698.     return;
  1699. }
  1700. #endif  /* !lint */
  1701.  
  1702.  
  1703. /*
  1704.  *----------------------------------------------------------------------
  1705.  *
  1706.  * openLog --
  1707.  *
  1708.  *    Open the dump log file and tee stderr so that all
  1709.  *      error messages are appended to the log.
  1710.  *
  1711.  * Results:
  1712.  *    None.
  1713.  *
  1714.  * Side effects:
  1715.  *      The log file is opened, and stderr is redirected to it.
  1716.  *
  1717.  *----------------------------------------------------------------------
  1718.  */
  1719.  
  1720. static void
  1721. openLog()
  1722. {
  1723.     int pfd[2];
  1724.     char buf[BUFSIZ];
  1725.     int fd;
  1726.  
  1727.     pipe(pfd);
  1728.     switch (fork()) {
  1729.  
  1730.     case -1:
  1731.     fatal("fork failed");
  1732.     /* NOTREACHED */
  1733.  
  1734.     case 0:     /* child */
  1735.         close(pfd[1]);
  1736.     if ((fd = open(LOGFILE, O_APPEND | O_WRONLY | O_CREAT, 0666)) < 0) {
  1737.         warning("Can't open log file %s", LOGFILE);
  1738.         return;
  1739.     }
  1740.     for (;;) {
  1741.         int r;
  1742.  
  1743.         switch (r = read(pfd[0], buf, sizeof(buf))) {
  1744.  
  1745.         case -1:
  1746.         fatal("Error reading from pipe");
  1747.         /* NOTREACHED */
  1748.  
  1749.         case 0:
  1750.         close(fd);
  1751.         exit(0);
  1752.  
  1753.         default:
  1754.         write(2, buf, r);
  1755.         if (write(fd, buf, r) != r) {
  1756.             warning("Error writing to %s", LOGFILE);
  1757.         }
  1758.         continue;
  1759.         }
  1760.     }
  1761.     /* NOTREACHED */
  1762.  
  1763.     default:    /* parent */
  1764.         close(pfd[0]);
  1765.     dup2(pfd[1], 2);        /* write all errors to log */
  1766.     break;
  1767.     }
  1768.     return;
  1769. }
  1770.  
  1771.  
  1772. /*
  1773.  *----------------------------------------------------------------------
  1774.  *
  1775.  * quote_string --
  1776.  *
  1777.  *    Expand all control characters in a string to the equivalent
  1778.  *      backslashed excape sequence.  For instance, a tab is converted
  1779.  *      to the two characters '\' and 't'.
  1780.  *
  1781.  * Results:
  1782.  *    None.
  1783.  *
  1784.  * Side effects:
  1785.  *    Modified the destination string.
  1786.  *
  1787.  *----------------------------------------------------------------------
  1788.  */
  1789.  
  1790. static void
  1791. quote_string(to, from)
  1792.     char *to;
  1793.     const char *from;
  1794. {
  1795.     int c;
  1796.  
  1797.     for (;;) {
  1798.     switch (c = *from++) {
  1799.  
  1800.     case '\0':
  1801.         *to = '\0';
  1802.         return;
  1803.  
  1804.     case '\\':
  1805.         *to++ = '\\';
  1806.         *to++ = '\\';
  1807.         break;
  1808.  
  1809.     case '\n':
  1810.         *to++ = '\\';
  1811.         *to++ = 'n';
  1812.         break;
  1813.  
  1814.     case '\t':
  1815.         *to++= '\\';
  1816.         *to++= 't';
  1817.         break;
  1818.  
  1819.     case '\f':
  1820.         *to++= '\\';
  1821.         *to++= 'f';
  1822.         break;
  1823.  
  1824.     case '\b':
  1825.         *to++= '\\';
  1826.         *to++= 'b';
  1827.         break;
  1828.  
  1829.     default:
  1830.         if (c < 0x20) {
  1831.         *to++ = '\\';
  1832.         *to++ = '0' + ((c >> 3) & 7);
  1833.         *to++ = '0' + (c & 7);
  1834.         break;
  1835.         } else {
  1836.         *to++ = c;
  1837.         }
  1838.     }
  1839.     }
  1840. }
  1841.  
  1842. /*
  1843.  *----------------------------------------------------------------------
  1844.  *
  1845.  * checkTape --
  1846.  *
  1847.  *    Check the dumpdates file to make sure it is safe to initialize
  1848.  *    the tape.  We do this by grepping through the last 100 lines
  1849.  *    of the dumpdates file to see if the tape has been used.
  1850.  *
  1851.  * Results:
  1852.  *    None.
  1853.  *
  1854.  * Side effects:
  1855.  *    Will exit with failure if it is not safe.
  1856.  *
  1857.  *----------------------------------------------------------------------
  1858.  */
  1859.  
  1860. static void
  1861. checkTape()
  1862. {
  1863.     char buf[1000];
  1864.     int status;
  1865.  
  1866.     sprintf(buf,"tail -100 %s | grep \"^%3.3d\" > /dev/null", DUMPDATES,
  1867.         tapeNumber);
  1868.     status = system(buf);
  1869.     if (status==0) {
  1870.     fprintf(stderr,"dump: tape %d recently used; init failed\n",
  1871.         tapeNumber);
  1872.     } else if (status==256 || status==1) {
  1873.     return;
  1874.     } else {
  1875.     fprintf(stderr,"dump: unable to do dumpdates safety check\n");
  1876.     }
  1877.     exit(123);
  1878. }
  1879.  
  1880. /*
  1881.  *----------------------------------------------------------------------
  1882.  *
  1883.  * gotoEOD --
  1884.  *
  1885.  *    Move tape to end-of-data.    
  1886.  *
  1887.  * Results:
  1888.  *    None.
  1889.  *
  1890.  * Side effects:
  1891.  *    The tape is moved.
  1892.  *
  1893.  *----------------------------------------------------------------------
  1894.  */
  1895.  
  1896. static void
  1897. gotoEOD()
  1898. {
  1899.     Dev_TapeCommand     args;
  1900.     ReturnStatus    status;
  1901.     int            files;
  1902.  
  1903.  
  1904.     debugp((stderr, "skipping to end of data\n"));
  1905.     args.command = IOC_TAPE_SKIP_EOD;
  1906.     args.count = 0;
  1907.     status = Fs_IOControl(archivefd, IOC_TAPE_COMMAND, sizeof(args),
  1908.     (char *) &args, 0, NULL);
  1909.     if (status != SUCCESS) {
  1910.     warning("Skip to end of data returned 0x%x", status);
  1911.     /*
  1912.      * If we are doing a restore then we want to do our best to
  1913.      * find the end of usable data. Otherwise we return an error.
  1914.      */
  1915.     fprintf(stderr, "Trying to find last file on tape\n");
  1916.     files = 0;
  1917.     rewindTape();
  1918.     /*
  1919.      * Skip over initial label.
  1920.      */
  1921.     status = skipFiles(1);
  1922.     if (status == SUCCESS) {
  1923.         files++;
  1924.         /*
  1925.          * Now skip over pairs of dump files and labels. 
  1926.          */
  1927.         while(1) {
  1928.         status = skipFiles(2);
  1929.         if (status != SUCCESS) {
  1930.             break;
  1931.         }
  1932.         files += 2;
  1933.         }
  1934.     }
  1935.     fprintf(stderr, "Tape ends with file %d\n", files);
  1936.     rewindTape();
  1937.     status = skipFiles(files);
  1938.     if (status != SUCCESS) {
  1939.         fatal("Can't find end of tape");
  1940.     }
  1941.     }
  1942. }
  1943.  
  1944. /*
  1945.  *----------------------------------------------------------------------
  1946.  *
  1947.  * skipFiles --
  1948.  *
  1949.  *    Skip the given number of files.
  1950.  *
  1951.  * Results:
  1952.  *    Return status from the ioctl.
  1953.  *
  1954.  * Side effects:
  1955.  *    The tape is moved around.
  1956.  *
  1957.  *----------------------------------------------------------------------
  1958.  */
  1959.  
  1960. static ReturnStatus
  1961. skipFiles(num)
  1962.     int        num;    /* Number of files to skip. */
  1963. {
  1964.     ReturnStatus    status;
  1965.     Dev_TapeCommand     args;
  1966.  
  1967.     debugp((stderr, "skipping %d files\n", num));
  1968.     args.command = IOC_TAPE_SKIP_FILES;
  1969.     args.count = num;
  1970.     status = Fs_IOControl(archivefd, IOC_TAPE_COMMAND, sizeof(args),
  1971.               (char *) &args, 0, (char *) 0);
  1972.     return status;
  1973. }
  1974.